#include <gio/gdesktopappinfo.h>
#include <gio/gio.h>
#include <libwnck/libwnck.h>
#include <glib.h>
#include <glib/gstdio.h>
#include <string.h>
#include <libgnome/libgnome.h>

#include "launchers_pad.h"
#include "launcher.h"
#include "config.h"
#include "globals.h"
//#include "nautilus_functions.h"

#define MAIN_GROUP              "Desktop Entry"
#define NAUTILUS_ICON_FOLDER    "folder"

static char * nautilus_link_get_link_icon_from_desktop (GKeyFile *key_file);


static GtkTargetEntry target_table[] =
{
    { (gchar *)"STRING",                     0, 0 },
    { (gchar *)"text/plain",                 0, 0 },
    { (gchar *)"text/uri-list",              0, 1 }
};


/**
 * launcher_new:
 * @id: launcher button number
 *
 * Create launcher. Launcher is a GtkButton widget.
 *
 * Return value: a new GtkWidget.
 **/
GtkWidget * launcher_new (guint id)
{
    GtkWidget * button = NULL;


    button = gtk_button_new_with_label (config.launcher_label);

    gtk_widget_set_size_request (button,
                                 config.launcher_size,
                                 config.launcher_size);

    // save launcher number for use in future
    g_object_set_data (G_OBJECT (button), "id", GUINT_TO_POINTER(id));

    g_signal_connect (GTK_OBJECT(button), "drag_data_received", GTK_SIGNAL_FUNC(launcher_on_drop), NULL);
    g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (launcher_on_clicked), NULL);
    g_signal_connect (G_OBJECT (button), "button-press-event", G_CALLBACK (launcher_on_right_click), NULL);

    gtk_drag_dest_set (button,
                       (GtkDestDefaults)(
                           GTK_DEST_DEFAULT_MOTION |
                           GTK_DEST_DEFAULT_HIGHLIGHT |
                           GTK_DEST_DEFAULT_DROP),
                       target_table,
                       sizeof (target_table)/sizeof (target_table[0]),
                       GDK_ACTION_COPY);

    return button; // GtkButton
}


/**
 * launcher_decorate:
 *   @widget:  GtkWidget *
 *   @filename: full path to .desktop file
 *
 * Load icon, label from .desktop file and set icon and tooltip
 * to launcher widget
 **/
void launcher_decorate (GtkWidget *widget, const gchar *filename)
{
    const gchar     * label;
    GDesktopAppInfo * appinfo=NULL;
    gboolean          result;
    gchar           * markup;


    // check file existens
    if (!g_file_test (filename, G_FILE_TEST_EXISTS))
    {
        // set default
        gtk_widget_set_tooltip_text (GTK_WIDGET(widget), config.launcher_label);
        gtk_button_set_image (GTK_BUTTON(widget), NULL);
        return;
    }

    appinfo = g_desktop_app_info_new_from_filename (filename);

    if (appinfo)
    {
        // label
        label = g_app_info_get_name (G_APP_INFO (appinfo));

        //gtk_button_set_label(GTK_BUTTON(widget), label);
        gtk_widget_set_tooltip_text (GTK_WIDGET(widget), label);

        // icon
        GtkWidget *icon_widget = NULL;
        icon_widget = launchers_pad_get_desktop_app_icon (appinfo);

        // box
        GtkWidget *box;
        box = gtk_vbox_new (FALSE, 2);
        gtk_widget_set_size_request(box, config.launcher_size-10, config.launcher_size-10);

        // top label in box
        GtkWidget *header;
        header = gtk_label_new(NULL);
        markup = g_strconcat("<small>", "", "</small>", NULL);
        gtk_label_set_markup (GTK_LABEL (header), markup);
        g_free((gpointer)markup);
        gtk_box_pack_start (GTK_BOX(box), GTK_WIDGET(header), FALSE, FALSE, 2);
        gtk_label_set_justify(header, GTK_JUSTIFY_LEFT);

        // icon in box
        gtk_box_pack_start (GTK_BOX(box), GTK_WIDGET(icon_widget), TRUE, TRUE, 2);

        // bottom label in box
        GtkWidget *footer;
        footer = gtk_label_new(NULL);
        markup = g_strconcat("<small>", "", "</small>", NULL);
        gtk_label_set_markup (GTK_LABEL (footer), markup);
        g_free((gpointer)markup);
        gtk_box_pack_end (GTK_BOX(box), GTK_WIDGET(footer), FALSE, FALSE, 2);
        gtk_label_set_justify (footer, GTK_JUSTIFY_LEFT);
        gtk_label_set_line_wrap (footer, TRUE);
        gtk_label_set_line_wrap_mode (footer, PANGO_WRAP_WORD_CHAR);

        // attach to launcher
        gtk_button_set_image (GTK_BUTTON(widget), box);
        gtk_button_set_image_position (GTK_BUTTON(widget),
                GTK_POS_TOP | GTK_POS_LEFT | GTK_POS_RIGHT | GTK_POS_BOTTOM);

        //gtk_widget_show_all (widget);
        gtk_widget_show (header);
        gtk_widget_show (icon_widget);
        gtk_widget_show (footer);
        gtk_widget_show (box);

        //gtk_button_set_image (GTK_BUTTON(widget), icon_widget);
        //gtk-button-images
        //gtk_widget_show (icon_widget);

        g_object_unref (appinfo);
    }
    else
    {
        // Can't load desktop file information by standart procedure
        // Try load over GKeyFile procedures
        result = launcher_decorate_try2(widget, filename);
        if (!result)
        {
            // Can't desktop file information
            // Set default label and image
            gtk_widget_set_tooltip_text (GTK_WIDGET(widget), config.launcher_label);
            gtk_button_set_image (GTK_BUTTON(widget), NULL);
        }
    }
}


/**
 * launcher_on_clicked:
 *   @widget:  GtkWidget *
 *   @data: NUL
 *
 * Event. Emited when launcher clicked
 * Read .desktop file and run application.
 * Run on current workspace
 **/
void launcher_on_clicked (GtkWidget *widget, gpointer data)
{
    GDesktopAppInfo *   appinfo = NULL;
    GList *             files = NULL;
    GdkAppLaunchContext *launch_context = NULL;
    GError *            error = NULL;
    gchar *             filename;
    gchar *             id;
    WnckWorkspace *     workspace;
    const gchar *       wspace_name;
    guint               wspace_id;


    // get current workspace name
    workspace =  wnck_screen_get_active_workspace (screen);
    wspace_name = wnck_workspace_get_name (workspace);

    // get launcher id
    id = launcher_get_id(widget);

    // full path to .desktop file
    filename = g_strjoin(NULL, config.dir, "/", wspace_name, "/", id, ".desktop", NULL);

    // check file existens
    if (g_file_test (filename, G_FILE_TEST_EXISTS))
    {
        // get applinfo
        appinfo = g_desktop_app_info_new_from_filename(filename);

        if (appinfo)
        {
            // bind to active workspace
            wspace_id = wnck_workspace_get_number (workspace);
            launch_context = gdk_app_launch_context_new ();
            gdk_app_launch_context_set_desktop (launch_context, wspace_id);

            // launch
            g_app_info_launch (
                G_APP_INFO (appinfo),
                files,
                G_APP_LAUNCH_CONTEXT(launch_context),
                &error);

            if (error)
                g_log (G_LOG_DOMAIN, G_LOG_LEVEL_ERROR, "%s", error->message);

            g_object_unref (appinfo);
        }
        else
        {
            // Run LINK
            GKeyFile    *key_file;
            GError      *error = NULL;
            const gchar *url;
            gboolean     result;


            // Load desktop-file
            key_file = g_key_file_new ();
            result = g_key_file_load_from_file (
                            key_file,
                            filename,
                            G_KEY_FILE_NONE,
                            NULL);
            if (!result)
            {
                g_key_file_free (key_file);
                return FALSE;
            }

            // Get URL
            url = g_key_file_get_string (key_file, MAIN_GROUP, "URL", NULL);

            // Open URL
            gnome_url_show(url, NULL);

            g_free((gpointer)url);
        }
    }

    g_free(filename);

    // close window
    if (config.close_on_launch)
        gtk_main_quit();
}



/**
 * launcher_on_drop:
 *   @widget:  GtkWidget *
 *   @context: GdkDragContext *
 *   @x: mouse x position
 *   @y: mouse y position
 *   @selection: URL, URI, Path
 *   @info; guint
 *   @time: guint
 *
 * Event. Emited when object dropped on launcher.
 **/
void launcher_on_drop (
    GtkWidget *widget, GdkDragContext *context,
    gint x, gint y,
    GtkSelectionData *selection,
    guint info, guint time)
{
    GFile *     source;
    GFile *     destination;
    gchar *     source_uri;
    gchar *     destination_uri;
    gchar **    source_uri_array;
    GError *    error=NULL;
    gchar **    ptr;
    gchar *     id;
    const gchar *filename;
    WnckWorkspace *workspace;
    const char *wspace_name;
    char *      wspace_dir;


    if (!selection)
        return;

    if (!selection->data)
        return;


    // get launcher id
    id = launcher_get_id(widget);

    // split source at \n
    source_uri_array = g_strsplit ((const gchar *)selection->data, "\r\n", 0);

    for (ptr = source_uri_array; *ptr != NULL; ptr++)
    {
        workspace =  wnck_screen_get_active_workspace (screen);
        wspace_name = wnck_workspace_get_name (workspace);

        source_uri = *ptr;

        // target desktop-file
        destination_uri = g_strjoin (NULL, URI_PREFIX, config.dir, "/", wspace_name, "/", id, ".desktop", NULL);

        if (source_uri == '\0')
            continue;

        source = g_file_new_for_uri(source_uri);
        destination = g_file_new_for_uri(destination_uri);

        // check and create workspace dir
        wspace_dir = g_strjoin (NULL, config.dir, "/", wspace_name, "/", NULL);

        if (!g_file_test(wspace_dir, G_FILE_TEST_EXISTS))
            if (g_mkdir (wspace_dir, S_IRWXU | S_IRGRP | S_IXGRP) != 0)
                g_log (G_LOG_DOMAIN, G_LOG_LEVEL_ERROR, "Can't create folder: %s", wspace_dir);

        g_free(wspace_dir);


        // if source is .desktop
        if (source_uri == ".desktop")
        {
            // copy .desktop file
            g_file_copy(source,
                        destination,
                        G_FILE_COPY_OVERWRITE | G_FILE_COPY_TARGET_DEFAULT_PERMS,
                        NULL,
                        NULL,
                        NULL,
                        &error);

            if (error)
                g_log (G_LOG_DOMAIN, G_LOG_LEVEL_ERROR, "%s", error->message);
        }
        else
        {
            // create .desktop file
            GKeyFile   *key_file;
            gsize       data_length;
            gchar      *data;
            gchar      *basename;
            gchar      *mime_type;


            key_file = g_key_file_new();
            g_key_file_set_string (key_file, MAIN_GROUP, "Encoding", "UTF-8");

            basename = g_file_get_basename(source);
            g_key_file_set_string (key_file, MAIN_GROUP, "Name", basename);
//            g_key_file_set_string (key_file, MAIN_GROUP, "Exec", "");
            g_key_file_set_string (key_file, MAIN_GROUP, "URL", source_uri);
            //mime_type = gnome_vfs_get_mime_type_for_name (source_uri);
            g_key_file_set_string (key_file, MAIN_GROUP, "Icon", "gnome-fs-regular");

            data = g_key_file_to_data (key_file, &data_length, NULL);

            g_file_replace_contents(
                        destination,
                        data,
                        data_length,
                        NULL,
                        FALSE,
                        G_FILE_CREATE_REPLACE_DESTINATION,
                        NULL,
                        NULL,
                        NULL);

            g_free((gpointer)data);
        }

        filename = g_filename_from_uri (destination_uri, NULL, &error);

        if (error)
            g_log (G_LOG_DOMAIN, G_LOG_LEVEL_ERROR, "%s", error->message);

        launcher_decorate(widget, filename);


        g_free(destination_uri);

        break; // only first item FIXME ?
    }

    g_strfreev(source_uri_array);

    gtk_drag_finish (context, TRUE, FALSE, time);
};


/**
 * launcher_get_id:
 *   @widget: GtkWidget *
 *
 * Get and convert to string launcher id.
 * Get from assigned with launcher data tagged as "id".
 *
 * Return value: string with id
 **/
gchar *launcher_get_id (GtkWidget *widget)
{
    guint        id;
    gpointer     id_ptr;
    static gchar id_str[STR_ID_LEN+1];


    id_ptr = g_object_get_data(G_OBJECT(widget), "id");
    id = GPOINTER_TO_UINT(id_ptr);
    g_snprintf(id_str, STR_ID_LEN, "%d", id);

    return id_str;
}


/**
 * launcher_clear:
 *   @widget: GtkWidget *
 *
 * Clear launcher. Remove image, text and source .desktop file
 * from config dir.
 **/
void launcher_clear (GtkWidget *widget)
{
    gchar *         id;
    gchar *         filename;
    const gchar *   wspace_name;
    WnckWorkspace * workspace;

    // file not exist
    // default label and image
    gtk_widget_set_tooltip_text (GTK_WIDGET (widget), config.launcher_label);
    gtk_button_set_image (GTK_BUTTON (widget), NULL);

    // get current workspace name
    workspace =  wnck_screen_get_active_workspace (screen);
    wspace_name = wnck_workspace_get_name (workspace);
    id = launcher_get_id (widget);
    filename = g_strjoin (NULL, config.dir, "/", wspace_name, "/", id, ".desktop", NULL);

    // check file existens and remove
    if (g_file_test (filename, G_FILE_TEST_EXISTS))
        g_remove (filename);

    g_free(filename);
}

/**
 * launcher_on_right_click:
 *   @widget: GtkWidget *
 *
 * Event. Emit when mouse button clicked.
 * If right Button clicked call clear procedure.
 **/
gboolean launcher_on_right_click (GtkWidget *widget,
                              GdkEventButton *event,
                              gpointer user_data)
{
    if (event->type == GDK_BUTTON_PRESS)
        if (event->button == 3) // right click
            launcher_clear (widget);

    return FALSE;
}


/*
 *
 */
gboolean launcher_decorate_try2 (GtkWidget *widget, const gchar *filename)
{
    GKeyFile    *key_file;
    GtkWidget   *icon_widget = NULL;
	const gchar *label;
	const gchar *icon;
    gboolean     result;


    key_file = g_key_file_new ();
    result = g_key_file_load_from_file (
                    key_file,
                    filename,
                    G_KEY_FILE_NONE,
                    NULL);
	if (!result)
    {
		g_key_file_free (key_file);
		return FALSE;
	}

	label = g_key_file_get_locale_string (key_file, MAIN_GROUP, "Name", NULL, NULL);
    icon  = nautilus_link_get_link_icon_from_desktop (key_file);

	if (!icon)
        return FALSE;

    //gtk_button_set_label(GTK_BUTTON(widget), label);
    gtk_widget_set_tooltip_text (GTK_WIDGET(widget), label);

    // icon
    icon_widget = gtk_image_new_from_icon_name (icon, GTK_ICON_SIZE_DIALOG);
    gtk_button_set_image (GTK_BUTTON(widget), icon_widget);
    gtk_widget_show (icon_widget);    //gtk-button-images

	g_free ((gpointer)icon);
	g_free ((gpointer)label);
	g_key_file_free (key_file);

	return TRUE;
}


/**
 * nautilus_link_get_link_icon_from_desktop:
 *
 * copied from nautilus: fm-desktop-icon-view.c
 */
static char * nautilus_link_get_link_icon_from_desktop (GKeyFile *key_file)
{
	char *icon_uri, *icon, *p, *type;

	icon_uri = g_key_file_get_string (key_file, MAIN_GROUP, "X-Nautilus-Icon", NULL);
	if (icon_uri != NULL) {
		return icon_uri;
	}

	icon = g_key_file_get_string (key_file, MAIN_GROUP, "Icon", NULL);
	if (icon != NULL) {
		if (!g_path_is_absolute (icon)) {
			/* Strip out any extension on non-filename icons. Old desktop files may have this */
			p = strchr (icon, '.');
                        /* Only strip known icon extensions */
			if ((p != NULL) &&
			    ((g_ascii_strcasecmp (p, ".png") == 0)
			     || (g_ascii_strcasecmp (p, ".svn") == 0)
			     || (g_ascii_strcasecmp (p, ".jpg") == 0)
			     || (g_ascii_strcasecmp (p, ".xpm") == 0)
			     || (g_ascii_strcasecmp (p, ".bmp") == 0)
			     || (g_ascii_strcasecmp (p, ".jpeg") == 0))) {
				*p = 0;
			}
		}
		return icon;
	}

	type = g_key_file_get_string (key_file, MAIN_GROUP, "Type", NULL);
	if (g_strcmp0 (type, "Application") == 0) {
		icon = g_strdup ("gnome-fs-executable");
	} else if (g_strcmp0 (type, "Link") == 0) {
		icon = g_strdup ("gnome-dev-symlink");
	} else if (g_strcmp0 (type, "FSDevice") == 0) {
		icon = g_strdup ("gnome-dev-harddisk");
	} else if (g_strcmp0 (type, "Directory") == 0) {
		icon = g_strdup (NAUTILUS_ICON_FOLDER);
	} else if (g_strcmp0 (type, "Service") == 0 ||
		   g_strcmp0 (type, "ServiceType") == 0) {
		icon = g_strdup ("gnome-fs-web");
	} else {
		icon = g_strdup ("gnome-fs-regular");
	}
	g_free (type);

	return icon;
}


